import ply.yacc as yacc

# Get the token map from the lexer.  This is required.
from lexique import tokens
from instructions.Mov import *
from instructions.Afc import *
from instructions.Add import *
from instructions.Sub import *
from instructions.Mul import *
from instructions.And import *
from instructions.Xor import *
from instructions.Or  import *
from instructions.Not import *
from instructions.Cmp import *
from instructions.Store import *
from instructions.Load import *
from instructions.Jmp import *
from instructions.Jeq import *
from instructions.Jne import *
from instructions.Jgt import *
from instructions.Jge import *
from instructions.Jlt import *
from instructions.Jle import *
from instructions.Push import *
from instructions.Pop import *
from instructions.Leave import *
from instructions.Call import *

from rom import Rom
from memory import Memory

start = 'Body'

ROM = None

# MOV

def p_mov(p):
    'Mov : MOV REGISTER REGISTER'
    ROM.addInstruction(Mov, p[2], p[3])
    
def p_afc(p):
    'Afc : AFC REGISTER SHARP CONSTANT'
    ROM.addInstruction(Afc, p[2], p[4])

# PUSH / POP

def p_push (p):
    'Push : PUSH REGISTER'
    ROM.addInstruction (Push, p[2])

def p_pop (p):
    'Pop : POP REGISTER'
    ROM.addInstruction (Pop, p[2])

# ADD / SUB / MUL

def p_add_1rv(p):
    'Add : ADD REGISTER SHARP CONSTANT'
    ROM.addInstruction(AddV, p[2], p[2], p[4])

def p_add_2r(p):
    'Add : ADD REGISTER REGISTER'
    ROM.addInstruction(Add, p[2], p[2], p[3])

def p_add_3r(p):
    'Add : ADD REGISTER REGISTER REGISTER'
    ROM.addInstruction(Add, p[2], p[3], p[4])

def p_sub_1rv(p):
    'Sub : SUB REGISTER SHARP CONSTANT'
    ROM.addInstruction(SubV, p[2], p[2], p[4])

def p_sub_2r(p):
    'Sub : SUB REGISTER REGISTER'
    ROM.addInstruction(Sub, p[2], p[2], p[3])

def p_sub_3r(p):
    'Sub : SUB REGISTER REGISTER REGISTER'
    ROM.addInstruction(Sub, p[2], p[3], p[4])

def p_mul_1rv(p):
    'Mul : MUL REGISTER SHARP CONSTANT'
    ROM.addInstruction(MulV, p[2], p[2], p[4])

def p_mul_2r(p):
    'Mul : MUL REGISTER REGISTER'
    ROM.addInstruction(Mul, p[2], p[2], p[3])

def p_mul_3r(p):
    'Mul : MUL REGISTER REGISTER REGISTER'
    ROM.addInstruction(Mul, p[2], p[3], p[4])

# AND / XOR / OR / NOT

def p_and_2r (p):
    'And : AND REGISTER REGISTER'
    ROM.addInstruction(And, p[2], p[2], p[3])

def p_and_3r (p):
    'And : AND REGISTER REGISTER REGISTER'
    ROM.addInstruction(And, p[2], p[3], p[4])

# CMP

def p_cmp (p):
    'Cmp : CMP REGISTER REGISTER'
    ROM.addInstruction(Cmp, p[2], p[3])

# LOAD / STORE

def p_store (p):
    'Store : STORE CONSTANT LPAREN REGISTER RPAREN REGISTER'
    ROM.addInstruction(Store, p[2], p[4], p[6])

def p_store_noval (p):
    'Store : STORE LPAREN REGISTER RPAREN REGISTER'
    ROM.addInstruction(Store, 0, p[3], p[5])

def p_load (p):
    'Load : LOAD REGISTER CONSTANT LPAREN REGISTER RPAREN'
    ROM.addInstruction(Load, p[2], p[3], p[5])

def p_load_noval (p):
    'Load : LOAD REGISTER LPAREN REGISTER RPAREN'
    ROM.addInstruction(Load, p[2], 0, p[4])

# JUMPS

def p_jmp (p):
    'Jmp : JMP LABEL'
    ROM.addInstruction(Jmp, p[2])

def p_eq (p):
    'Jmp : JEQ LABEL'
    ROM.addInstruction(Jeq, p[2])

def p_jne (p):
    'Jmp : JNE LABEL'
    ROM.addInstruction(Jne, p[2])

def p_jlt (p):
    'Jmp : JLT LABEL'
    ROM.addInstruction(Jlt, p[2])

def p_jle (p):
    'Jmp : JLE LABEL'
    ROM.addInstruction(Jle, p[2])

def p_jge (p):
    'Jmp : JGE LABEL'
    ROM.addInstruction(Jge, p[2])

def p_jgt (p):
    'Jmp : JGT LABEL'
    ROM.addInstruction(Jgt, p[2])

# LEAVE / CALL

def p_leave (p):
    'Leave : LEAVE'
    ROM.addInstruction(Leave)

def p_call (p):
    'Call : CALL LABEL'
    ROM.addInstruction(Call, p[2])

# LABEL

def p_label (p):
    'Label : LABEL COLON'
    ROM.addLabel(p[1])

# BODY

def p_body (p):
    """ Body : 
    | Mov NEWLINE Body
    | Afc NEWLINE Body
    | Pop NEWLINE Body
    | Push NEWLINE Body
    | Add NEWLINE Body
    | Sub NEWLINE Body
    | Mul NEWLINE Body
    | And NEWLINE Body
    | Cmp NEWLINE Body
    | Load NEWLINE Body
    | Store NEWLINE Body
    | Leave NEWLINE Body
    | Call NEWLINE Body
    | Jmp NEWLINE Body
    | Label NEWLINE Body """
    pass

# Error rule for syntax errors
def p_error(p):
    print "Syntax error in input [" + str(p) + "] !"

# Build the parser
parser = yacc.yacc()

def parse(code):
    global ROM
    ROM = Rom(Memory())
    parser.parse(code)
    return ROM
